package com.atguigu.gmall.activity.controller;

import com.atguigu.gmall.activity.component.SeckillLocalCache;
import com.atguigu.gmall.activity.mq.to.SeckillSuccessTo;
import com.atguigu.gmall.activity.service.SeckillService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.common.util.AuthContextHolder;
import com.atguigu.gmall.feign.order.OrderFeignClient;
import com.atguigu.gmall.model.activity.SeckillGoods;
import com.atguigu.gmall.model.order.OrderInfo;
import com.atguigu.gmall.mq.MqConst;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rabbitmq.client.impl.AMQContentHeader;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMethodMappingNamingStrategy;

import javax.servlet.http.HttpServletRequest;
import java.sql.ResultSet;

@RequestMapping("/api/activity/seckill")
@RestController
public class SeckillApiController {

    @Autowired
    SeckillService seckillService;

    @Autowired
    SeckillLocalCache seckillLocalCache;

    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Autowired
    OrderFeignClient orderFeignClient;


    //立即抢购 seckill/auth/getSeckillSkuIdStr/38
    @GetMapping("/auth/getSeckillSkuIdStr/{skuId}")
    public Result getSeckillCode(@PathVariable("skuId") Long skuId, HttpServletRequest request) {

        String userId = AuthContextHolder.getUserId(request);
        //生成秒杀码 MD5（skuId + 用户id）
        String code = seckillService.generateSeckillCode(skuId, userId);
        if ("error".equals(code)) {
            return Result.build(null, ResultCodeEnum.SECKILL_NO_START);
        }
        return Result.ok(code);
    }

    /**
     * /api/activity/seckill/auth/seckillOrder/46?skuIdStr=秒杀码
     */
    @PostMapping("/auth/seckillOrder/{skuId}")
    public Result seckillOrder(@RequestParam("skuIdStr") String skuIdStr,
                               @PathVariable("skuId") Long skuId,
                               HttpServletRequest request) {
        //合法性校验
        //1、校验秒杀码是否正确
        String userId = AuthContextHolder.getUserId(request);
        Boolean aBoolean = seckillService.checkSeckillCode(skuId, userId, skuIdStr);
        if (!aBoolean) {
            //秒杀码错误
            return Result.build(null, ResultCodeEnum.SECKILL_ILLEGAL);
        }
        //2、校验状态位，先不去校验信号量，先去校验内存状态位（延迟更新，redis真的没了，他才会更新没有）
        SeckillGoods goods = seckillLocalCache.getSeckillGoodsBySkuId(skuId);
        if ((goods.getNum() - goods.getStockCount()) <= 0) {
            //内存状态位没有了，秒完了
            return Result.build(null, ResultCodeEnum.SECKILL_FINISH);
        }
        // 3、接下来判断该userId是否已经下过单了 防重检查
        //未来只要抢购成功，我们会给redis中与保存这个人的秒杀信息，查redis确认
        boolean bool = seckillService.checkRepeat(skuId, userId, skuIdStr);
        if (!bool) {
            //只做一次
            return Result.build(null, ResultCodeEnum.REPEAT_SUBMIT);
        }

        //4、扣库存，获取信号量
        boolean b = seckillService.seckillStockLocked(skuId, skuIdStr, userId);
        if (!b) {
            //秒杀完了，通知其他本地缓存，更新skuId的数量，一旦发现有人秒杀失败了，redis广播一下


            return Result.build(null, ResultCodeEnum.SECKILL_FINISH);
        }
        //扣库存成功，预示着秒杀成功，发消息给mq，该用户，秒杀成功
        rabbitTemplate.convertAndSend(
                MqConst.SECKILL_EXCHANGE,
                MqConst.SECKILL_SUCCESS_RK,
                new SeckillSuccessTo(userId, skuId, skuIdStr));

        return Result.ok();

    }

    @GetMapping("/auth/checkOrder/{skuId}")
    public Result checkSeckillOrder(@PathVariable("skuId") Long skuId, HttpServletRequest request) throws JsonProcessingException {
        //211 215 218 其他
        //ResultCodeEnum.SECKILL_RUN    排队中
        //ResultCodeEnum.SECKILL_SUCCESS    秒杀成功
        //ResultCodeEnum.SECKILL_ORDER_SUCCESS  下单成功

        String userId = AuthContextHolder.getUserId(request);
        ResultCodeEnum status = seckillService.checkOrderStatus(skuId, userId);
        return Result.build(null, status);
    }

    @PostMapping("/auth/submitOrder")
    public Result submitOrder(@RequestBody OrderInfo orderInfo,HttpServletRequest request) throws JsonProcessingException {
        String userId = AuthContextHolder.getUserId(request);
        orderInfo.setUserId(Long.parseLong(userId));
        OrderInfo info = orderFeignClient.submitSeckillOrder(orderInfo);
        //重新给redis中存一份，方便状态检查
        String json = new ObjectMapper().writeValueAsString(info);
        redisTemplate.opsForValue().set(RedisConst.SECKILL_USER + info.getUserId(),json);

        return Result.ok(info.getId());
    }
}
